<html xmlns="http://www.w3.org/1999/xhtml" id="delegates">
<head>
    <title>デリゲート</title>
		<othercredit role="translator">
		  <firstname>Yoshihiro</firstname>
			<surname>ICHIYANAGI</surname>
			<contrib>2005/12/03 3.0.2用翻訳初版</contrib>
		</othercredit>
		<othercredit role="translator">
		  <firstname>Yoshihiro</firstname>
			<surname>ICHIYANAGI</surname>
			<contrib>2005/12/14 3,1対応 HTML化</contrib>
		</othercredit>
</head>

<body>

<h1>デリゲート</h1>
 

<p>
この章では、デリゲート(属性値が変化した時、OpenLaszloアプリケーションの複数の異なるパーツが
お互いに通知するために利用されるしくみの一つ)の使い方を説明します。
</p>
<p>
一般的には、(タグではなく)Javaスクリプトで生成されたオブジェクトについてのデリゲート、のみを認識すれば十分でしょう。
例えば&lt;view&gt;のようなタグによって生成されるオブジェクトについては、<xref linkend="methods-events-attributes"/>で記述されているように、
'onfoo' あるいは '&lt;method event=...&gt;'構文のイベントハンドラーを利用して通知を管理することができます。
この構文は、あなたに代ってデリゲートの世話をしてくれます。それでも背後にデリゲートは存在し、システムは見えないところで
デリゲートを管理しています。デリゲートを理解することは、タグとスクリプトベースのイベント構文の間の関係を
理解するのに役立ちます。
</p>
<p>この章の最後のセクションでは、どのようにデリゲートされるかを他のプログラム言語と比較しながら説明します。</p>


<!--=========================================================================-->
<!-- Major sub-heads in h2, etc                                                               -->
<!--=========================================================================-->
<?ignore
<h2><a name="overview">概要</a></h2>

<p> </p>

<!-- See other chapters in the D3 guide and also the wiki for more informtion on formatting chapters --> 
<!-- Here is a list of some topics you may want to discuss in this chapter-->


 <h2>LZXのpoint-to-pointイベントシステム</h2>
<fixme>
Link to appropriate section of the "methods, attributes events " chapter
</fixme>
<fixme>
 No 'broadcast'; no trickle up or down
 Event: message that attribute has changed value(??)
</fixme>
<h3>デリゲート: インスタンスの名前付きメソッド</h3>
?>


<h2>概要</h2>
<p>
デリゲートの目的は、ランタイムで、あるメソッドへのイベントを割り当てることです。
したがって、「デリゲートでイベントを登録すること」は、一時的に、デリゲートによって呼び出されるイベントを
単にメソッドに割り当てることを意味します。
その割り当てられたイベントは、あなたがデリゲートを"unregister"するまで、そのメソッドに割り当てられます。
これは、イベントが起こるとき、そのメソッドが実行されることを意味します。
</p>
<p>
重要なことは、コンパイル時にデリゲートを呼び出すイベント名を知らなくても、デリゲートを利用できることです &#8212;
イベント名は、アプリケーション実行の間に生成される値をパラメータとして渡すことができます。
</p>
<p>
LZXでは、デリゲートとイベントは互いについて定義し合っています。
デリゲートはメソッドを呼び出す、名前付きのオブジェクトであり、イベントはデリゲートを保持するオブジェクトとなります。
</p>
<p>
イベントが発生する時、そのイベントのすべてのデリゲートを順番に呼び出します。
つまりデリゲートは、インスタンスの名前付きメソッドと見なすことが可能となります。
</p>
<p>
デリゲートは、タグによって生成されたオブジェクトも同様に、イベントに関連付けられますが、
一般的には、明示的に生成されるデリゲートは、(タグでではなく)スクリプト内で生成されたオブジェクトのために利用されます。
</p>

<p>
コンパイル時、どんなイベントが発生するかわからない場合も時々あるので、そんなときデリゲートは必要になります。
例えば、一つの<classname>window</classname>があるとして、windowがクリックされたときはいつでも呼ばれるメソッドがほしいとします。
その場合、<code>&lt;window onclick="clickhandler()"&gt;</code>のようなタグを使用するでしょう。
しかしながら、イベントが発生する時、イベントの望む動作がある条件に依存する場合もあります。
そのような場合に、デリゲートを使用でしょう。
</p>

<h3>LzDelegate</h3>
<p>
デリゲートを生成し管理するために、<classname link="true">LzDelegate</classname>クラスを使います。
</p>
<p>
デリゲートを生成するための構文: </p>
<pre>
LzDelegate(object, method, sender, event)
</pre>
<p>
LzDelegateの3番目と4番目の引数は、オプションで: </p>
<pre>
 var del = new LzDelegate(object, method, sender, event); 
</pre>
<p>
以下と同じです:
</p>
<pre>
 var del = new LzDelegate(object, method); 
 del.register(sender, event);
</pre> 

<h3>デリゲートとタグ生成によるイベント間の関係</h3>

<p>
<classname link="true">LzDelegate</classname>クラスは、スクリプト内でデリゲートを生成するために使用されます。
</p>
<p>
すなわち、以下によりメソッドをイベントに張り付けることができます:</p>
<pre>
    &lt;method event="eventName" reference="eventSender"&gt;
       ...what to do...
    &lt;/method&gt;
</pre>
<p>
しかしコンパイル時に<code>eventName</code>あるいは<code>eventSender</code>がわからない場合には動的な方法を使う必要があります:
</p>
<pre>

     &lt;method name="methodName"&gt;
       ...what to do...
     &lt;/method&gt;

     &lt;method name="createDelegate&gt;
     this.myDel = new LzDelegate(this, "methodName", eventSender, "eventName");
     &lt;/method&gt;
</pre>
<p>
イベントハンドラは、自動的にデリゲートを生成し登録するすべての仕事を取扱います:
</p>
<pre>
onclick="do something or other"; 
</pre>
<p>
これを拡張して:
</p>
<pre>
 &lt;method event="onclick" target="this"&gt; 
 do something or other; 
 &lt;/method&gt; 
</pre>
<p>
(targetはオプションで、デフォルトは<code>this</code>) これを拡張して: </p>
<pre>
 // make up a unique method name 
 var uid = $m + &lt;unique id&gt; 
 // make a method of that name to run the onclick code 
 this.$m = function () { ; }; 
 // make a delegate for that method 
 var del = new LzDelegate(this, $m); 
 // register it to receive onclick events 
 del.register(this, 'onclick'); 
</pre>
<p>
以下の例は、<classname>LzDelegate</classname>の利用法を説明しています。
</p>

<h3> Example: LzDelegateをつかってランタイムでイベントの登録をするためには </h3>

<p>
以下の例は、簡単な記憶ゲームです。ボタンが一度押された時、特になにもレポートされません。
ボタンが2回押されたなら、緑のステータスバーがこの結果を示すメッセージとしてレポートされます。
このゲームは、'start over'ボタンを押すことにより、リスタートすることができます。
</p>

<p>
注意することは、各ボタンに対して、<code>onclick</code>イベントが発生する時、canvas上の<method>regbutton</method>メソッドが
呼ばれるということです。もしまだデリゲートが存在していないならば、<method>regbutton</method>メソッドのための
デリゲートを生成した後、いまクリックされたボタンの'onclick'イベントを登録します。
</p>
<h4>コントロールの流れ</h4>
<p>
一度もクリックされたことがないボタンがクリックされると、(デリゲートは生成されますが)特別なにも表示されません。
しかしながら、以前クリックされたボタンがクリックされた場合、デリゲートは、結果を示すメッセージを表示する
<method>buttonclickedagain</method>を呼び出します。
これは、既にクリックされたボタンによって、'onclick'イベントがデリゲートとともに登録されているからです。</p>
<p>
'start over'ボタンをクリックすることにより、デリゲートからすべてのイベントを取り消し、メッセージを'Nothing special'にリセットします。
</p>

<example title="ランタイムでイベントを登録するには">
&lt;canvas height="100"&gt; 
    &lt;view width="80"&gt; 
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/&gt;
        &lt;wrappinglayout/&gt;
    &lt;/view&gt; 
    &lt;text id="statusText" bgcolor="green" resize="true"/&gt; 
    &lt;button text="start over" onclick="canvas.startover()"/&gt;
    &lt;simplelayout axis="y"/&gt;

    &lt;method name="regbutton" args="b"&gt; 
        if( typeof this.del == "undefined" )  {
            this.del = new LzDelegate( this, "buttonclickedagain" ); 
        }      

        this.del.register( b, "onclick" );
    &lt;/method&gt; 

    &lt;method name="startover"&gt;
        this.del.unregisterAll(); 
        this.reset();
    &lt;/method&gt;

    &lt;method name="reset"&gt; 
        statusText.setAttribute("text", "Nothing special");
    &lt;/method&gt; 

    &lt;method name="buttonclickedagain"&gt; 
        statusText.setAttribute("text", "That button was clicked two or more times");
    &lt;/method&gt; 
&lt;/canvas&gt;
</example>
<h2>デリゲートとメモリ管理</h2>
<p>
オブジェクトを削除すると、-- 例えば、viewの場合 -- オブジェクトを保持するのに使われたメモリを解放します。
しかしながら、viewを消去しても、それに関係したデリゲートを削除されません。
デリゲートによって使用されたメモリを解放するには、マニュアルでデリゲートを削除しなければなりません。
</p>
<h3>メモリ管理の例</h3>
<p>
デリゲートを使って、自動的にメソッドをイベントにアタッチするには:
</p>
<example extract="false" title="デリゲートとメモリ">
&lt;class ...&gt;
   &lt;method name="doit"&gt; ... &lt;/method&gt;

   &lt;method event="init"&gt;
     super.init();
     this.myDel = new LzDelegate(this, 'doit', libraryName, 'onload');
   &lt;/method&gt;
&lt;!--
Be sure to clean up your delegate manually, if you destroy
instances, or the application will "leak" memory:--&gt;

   &lt;method name="destroy"&gt;
     this.myDel.unregisterAll();  // "destroys" delegates
     super.destroy();
   &lt;/method&gt;

&lt;/class&gt;
</example>
<h2>LzTimerを使って時間の経過をみるために</h2>

<p>
以下の例では、経過した秒数を表示するビジュアルタイマを生成します。
<tagname>text</tagname>ノードが初期化される時、<method>updateTimer</method>メソッドをコールします。
<method>updateTimer</method>は最初、経過秒数を指し示すテキストを更新し、secondsPassed属性をインクリメントします。
初回、<method>updateTimer</method>が呼ばれると、<method>updateTimer</method>を単にコールする新しいデリゲートを生成します、
そしてこの新しく生成されたデリゲートを毎秒コールする、タイマが作成されます。
デリゲートによって各経過時刻に、<method>updateTimer</method>が呼び出される時、
毎回(効率が悪い)新しいタイマを生成する代りに、<method>LzTimer.resetTimer</method>が呼び出されます。
</p>

<example title="LzTimerを使って秒数タイマを生成">
&lt;canvas height="20"&gt; 
    &lt;text oninit="updateTimer()"&gt;
        &lt;attribute name="secondsPassed" type="number" value="0"/&gt; 

        &lt;method name="updateTimer"&gt;
            this.setAttribute('text', this.secondsPassed );
            this.secondsPassed++; 

            if( typeof this.del == "undefined" ) { 
                this.del = new LzDelegate( this, "updateTimer" );
                LzTimer.addTimer( this.del, 1000 );
            } else {
                LzTimer.resetTimer( this.del, 1000 );
            }
        &lt;/method&gt;
    &lt;/text&gt; 
&lt;/canvas&gt;
</example>

<h2> <classname>LzDelegate</classname>を使って最後に複製される(replicated)ビューの初期化を確認するには </h2>

<p>
以下の例では、最後の<tagname>text</tagname>オブジェクトに対して複製と初期化が行われた時、
緑色の<tagname>text</tagname>に'The last view has been replicated'をセットします。
このタスクを実行するために、最初に複製される<tagname>text</tagname>上に明確にdatapathを宣言します。
次に新しい<tagname>text</tagname>ノードが(初期化でなく)複製されたときに発生する、onclonesイベントを設定します。
onclonesイベントの内部では、最後に複製されるクローンを特定して、LzDelegateをつかってoninitイベントを登録します。
最後の<tagname>text</tagname>ノードが初期化された時、デリゲートは緑色の<tagname>text</tagname>ノードのテキストを
更新する"replicationComplete"メソッドをコールします。
</p>

<p>
このテクニックはまた、<event>oninit</event>イベントの代りに<event>onload</event>イベントが単に登録されることにより、
リソースがロードされた最後のビューを見つけるのに利用することができます。
</p>
<example title="最後にviewが複製される時に発生するイベントを登録">
&lt;canvas height="125"&gt; 
    &lt;dataset name="people"&gt;
        &lt;people&gt; 
            &lt;person name="John"/&gt; 
            &lt;person name="Eric"/&gt; 
            &lt;person name="Andrew"/&gt; 
            &lt;person name="chrisk"/&gt; 
            &lt;person name="Sarah"/&gt; 
            &lt;person name="Pablo"/&gt; 
            &lt;person name="Adam"/&gt; 
        &lt;/people&gt;
    &lt;/dataset&gt; 

    &lt;view&gt;
        &lt;text&gt;
            &lt;datapath xpath="people:/people/person/@name"&gt;
                &lt;method event="onclones"&gt;
                    var lastclone = this.clones[ this.clones.length - 1 ];

                    if( typeof this.del == "undefined" ) {
                        this.del = new LzDelegate( this, "replicationComplete") 
                    } else {
                        this.del.ungregisterAll();
                    }

                    this.del.register( lastclone, "oninit"); 
                &lt;/method&gt;

                &lt;method name="replicationComplete"&gt;
                    lastRepText.setText("The last view has been replicated"); 
                &lt;/method&gt;
            &lt;/datapath&gt;
        &lt;/text&gt;
        &lt;simplelayout axis="y"/&gt;
    &lt;/view&gt;

    &lt;text id="lastRepText" bgcolor="green" resize="true"&gt; 
        Replication incomplete
    &lt;/text&gt;
   
    &lt;simplelayout axis="y"/&gt; 
&lt;/canvas&gt; 
</example>
<h2>属性としてのデリゲート</h2>
<p>
デリゲートはオブジェクトであり、同様に他のオブジェクトの属性にもすることができます。
例えば、以下を考えてみましょう:</p>
<example extract="false" title="属性としてのデリゲート">
&lt;button text="clickme"&gt;
    &lt;attribute name="mydel" type="expression"
               value="$once{new LzDelegate(this, 'handler')}"
</example>
<p>
上のコードは、ボタンがインスタンス化される時、<code>mydel</code>というデリゲートを生成します。
デリゲートを宣言するというテクニックは、読みやすくなるというメリットがあるとともに、
ただ一つのデリゲートを生成するという安全性も確保できるでしょう。
</p>
<p>このテクニックを使う例として、XML-rpc章の<a href="${dguide}rpc.html#delegate-as-attribute">この例</a>を参照してください。</p>
<h2>他の言語におけるデリゲート</h2>
<p>
ここでは多分あなたにとって馴染のあるその他のプログラミング言語におけるデリゲートについての簡単な議論をしてみます。
LZXでデリゲートを利用するためには、ここの議論はとくに必要ではありません。
</p>
<p>
デリゲートは'メソッド ポインタ'です。(オブジェクトを確保しない関数ポインタとの対比として)ことわざのように言えば:
「それを与えよ、オブジェクトoのメソッドmを呼ぶ時に。」
Javaでは、デリゲートと同じ効果を得るには'anonymous inner class'を使用します。
(つまりJavaでは、関数を持つインスタンスを生成します。)
Lispでは、クロージャを使います。(つまりLispでは、contextを持つ関数を生成します。)
[JavaとLispの方法は、同じコインのちょうど2つの側面です。]
</p>
<p>
基本的には: </p>
<pre>

 // constructor 
 LzDelegate = function(o, m) { this.o = o; this.m = m; } 
 LzDelegate.prototype.execute = function () { with (this) { return o[m](); } }; 

 var del = new LzDelegate(object, 'method'); 
 del.execute(); 
</pre>
<p>
上と下の記述は同じです: </p>
<pre>

 // constructor 
 function makeDelegate (o, m) { return function () { return o[m](); }; }; 

 var del = makeDelegate(object, 'method'); 
 del(); 
</pre>
<p>
コンテキスト'o'と'm'を確保しそれを呼び出す関数(メソッド)を持つインスタンスと、
クロージャによってコンテキスト'o'と'm'を確保する関数とを、ここで比較することができるでしょう。
</p>


<?ignore
<h2>Services that are based on delegates</h2>

<fixme>
This chapter needs to be flushed out with examples of custom events, an explanation of lzdelegate, an example using timers
</fixme>
<fixme>
"listens" for event
 Understanding the "registry" (not to be confused with windows registry)
 When are events triggered?
i.  on data
ii.  on percent
iii.  on init
iv.  etc
v.  Forward reference to 'initialization/instantiation' chapter
</fixme>
 ?>

</body>
</html>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2004 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
